package register

import (
	"fmt"
	"github.com/sirupsen/logrus"
	"time"
	"log"
	"strings"
	"github.com/valyala/fasthttp"
	"encoding/json"
	"math/rand"
	"errors"
)

type filter struct {
	client *Client
}



func (f *filter) responseVideo(request BrowserGet, nodes *NodeStates, remoteIp string) bool {
	//isOk := false
	log.Printf("[info]: responseVideo remoteIp:%v", remoteIp)
	//less than 5 return all nodes
	//if len(nodes) > 5 {
	//	nodes.RegionFilter(remoteIp, g.regionDecoder, func(states NodeStates) bool {
	//		if g.nodeSchedule(request, states) {
	//			isOk = true
	//			return false
	//		}
	//		return true
	//	})
	//	if isOk {
	//		return true
	//	}
	//}

	// TODO 重复过滤
	return f.nodeSchedule(request, nodes)
}


func (f *filter)  nodeSchedule(request BrowserGet, nodes *NodeStates) bool {
	logrus.Debugf("[GetHandler.nodeSchedule] into len(%d)", len(nodes.nodeAddress))
	result := BrowserGetResponse{}
	var natFilterNodes []*BrowserGetNodeInfo
	noInLocal := new(Scheduler)
	if len(nodes.nodeAddress) == 0 {
		return false
	}
	//过滤网络类型
	for _, node := range nodes.nodeAddress {
		mac := strings.ToLower(node.MacAddr)
		log.Printf("[info]: node scheduler mac:%s",mac)
		f.client.server.lock.Lock()
		peer, ok := f.client.server.clients[mac]
		f.client.server.lock.Unlock()
		if !ok {

			noInLocal.Nodes = append(noInLocal.Nodes, &MacAddr{Mac:mac})

			continue
		}
		nodeInfo, natFilteFlag, err := f.getNodeInfo(&peer.nodeAnnounce, request.Host, request.Uri, request.Md5)
		if err != nil {
			log.Printf("[error]: get in local node info err:%v", err)
			continue
		}
		if !natFilteFlag {
			result.Nodes = append(result.Nodes, nodeInfo)
		} else {
			natFilterNodes = append(natFilterNodes, nodeInfo)
		}
	}
	if len(noInLocal.Nodes) != 0 {

		log.Printf("push to register server body: %v",noInLocal)
		const baseUrl = "get"
		fastClient := &fasthttp.Client{
			//ReadTimeout: 5*time.Second,
		}
		body, err := json.Marshal(noInLocal)
		log.Printf("[info]: get no in local node:%v", string(body))
		if err != nil {
			log.Printf("[error]: get not in local json marshal err:%v", err)
			goto next
		}
		req := fasthttp.AcquireRequest()
		req.Header.SetMethod("POST")
		req.SetRequestURI(baseUrl)
		req.SetHost(f.client.server.remoteHost)
		req.SetBody(body)
		resp := fasthttp.AcquireResponse()
		if err := fastClient.DoTimeout(req, resp, 10*time.Second); err != nil {
			log.Printf("node push to server:%s ", err)
		}
		if resp.StatusCode() != fasthttp.StatusOK {
			log.Printf("[error]: get not in local info err:%d", resp.StatusCode())
			goto next
		}
		log.Printf("[info]: node get in station 1:%v", len(resp.Body()))
		if len(resp.Body()) != 0 {
			var getNode []NodeAnnounce
			log.Printf("[info]: node get in station 2:%v", string(resp.Body()))
			err = json.Unmarshal(resp.Body(), &getNode)
			if err != nil {
				log.Printf("[error]: get not in local resp json unmarshal err:%v", err)
				goto next
			}
			for _, peer := range getNode {
				nodeInfo, natFilteFlag, err := f.getNodeInfo(&peer, request.Host, request.Uri, request.Md5)
				if err != nil {
					log.Printf("[error]: get not in local node info err:%v", err)
					continue
				}
				if !natFilteFlag {
					result.Nodes = append(result.Nodes, nodeInfo)
				} else {
					natFilterNodes = append(natFilterNodes, nodeInfo)
				}
			}
		}

	}

next:
	if len(result.Nodes) < 5 {
		if len(result.Nodes) == 0 && len(natFilterNodes) == 0 {
			return false
		}
		result.Nodes = append(result.Nodes, natFilterNodes...)
		if len(result.Nodes) < 5 {
			f.client.jsonResponse(result)
		} else {
			result.Nodes = result.Nodes[:5]
			f.client.jsonResponse(result)
		}
		return true

	} else {
		result.Nodes = f.getRandNode(result.Nodes)
		f.client.jsonResponse(result)
		return true
	}

	return false
}

func (f *filter) getRandNode(result []*BrowserGetNodeInfo) (response []*BrowserGetNodeInfo) {

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	randRecord := make(map[int]int)
	nodesSize := len(result)

	for i := 0; i < nodesSize && len(response) <= 5; i++ {
		index := r.Intn(nodesSize)
		if _, exist := randRecord[index]; exist {
			continue
		}
		randRecord[index] = 1

		response = append(response, result[index])
	}
	return response
}

func (f *filter)  getNodeInfo(n *NodeAnnounce, Host, Uri, Md5 string) (*BrowserGetNodeInfo, bool, error) {
	natFilteFlag := false
	nodeInfo := BrowserGetNodeInfo{}

	if len(n.Sdps) < 1 {
		return &nodeInfo, natFilteFlag, errors.New(
			fmt.Sprintf("[GetHandler.getNodeInfo]:Sdps.len < 1 "))
	}
	logrus.Debugf("%v ", f.client.server.clients)

	if time.Now().Unix()-n.Time > n.Timeout {
		return &nodeInfo, natFilteFlag,
			errors.New(fmt.Sprintf("[GetHandler.getNodeInfo]: timeout"))
	}

	if n.Nat >= 4 {
		natFilteFlag = true
	}

	//nodeInfo = BrowserGetNodeInfo{
	//	Host: Host,
	//	Uri:  Uri,
	//	Md5:  Md5,
	//}
	nodeInfo.Host = Host
	nodeInfo.Uri = Uri
	nodeInfo.Md5 = Md5

	nodeInfo.PeerId = n.PeerId
	nodeInfo.Sdp = NodeOffer{
		Sdp:  n.Sdps[0].Offer.Sdp,
		Type: n.Sdps[0].Offer.Type,
	}
	nodeInfo.OfferId = n.Sdps[0].OfferId

	n.Sdps = n.Sdps[1:]

	return &nodeInfo, natFilteFlag, nil
}

func (f *filter)  responseNoVideo(request BrowserGet) {
	nodeInfo := &BrowserGetNodeInfo{
		Host:      request.Host,
		Uri:       request.Uri,
		Md5:       request.Md5,
		ErrorCode: "4004",
		Msg:       "No such file",
	}
	result := BrowserGetResponse{}
	result.Nodes = append(result.Nodes, nodeInfo)
	log.Printf("[GetHandler.responseNoVideo] no such file: %s %s", request.Host, request.Uri)
	f.client.jsonResponse(result)
}